package com.kynnnn.cloud.springboot_quartz.service;

import com.kynnnn.cloud.springboot_quartz.entity.ScheduleJobConfig;
import com.kynnnn.cloud.springboot_quartz.exception.ScheduleJobException;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;

/**
 * <h1>定时任务操作类</h1>
 *
 * @author Zhudiwei
 * @date 2021/10/13
 **/
@Service
@Slf4j
public class QuartzService {

    @Autowired
    private Scheduler scheduler;

    /**
     * <h2>新增定时任务</h2>
     *
     * @param config {@link ScheduleJobConfig}
     */
    public void add(ScheduleJobConfig config) {

        log.info("新增定时任务，定时任务名称->[{}]，任务组名称->[{}]，全类名->[{}]，七子表达式->[{}]",
                config.getJobName(),
                config.getJobGroupName(),
                config.getClazz(),
                config.getExpression()
        );

        try {
            // 启动调度器
            scheduler.start();

            @SuppressWarnings("all")
            Class<? extends QuartzJobBean> clazz = (Class<? extends QuartzJobBean>) Class.forName(config.getClazz());

            // 构建job信息
            JobDetail jobDetail = JobBuilder
                    .newJob(clazz)
                    .withIdentity(config.getJobName(), config.getJobGroupName())
                    .build();

            // 表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(config.getExpression())
                    // 不触发立即执行，等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
                    .withMisfireHandlingInstructionDoNothing();

            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(config.getJobName(), config.getJobGroupName())
                    .withSchedule(scheduleBuilder)
                    .build();

            scheduler.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            throw new ScheduleJobException(String.format("向Quartz中新增定时任务失败，原因：%s", e.getMessage()));
        } catch (ClassNotFoundException ex) {
            throw new ScheduleJobException(String.format("查无此类名：%s", config.getClazz()));
        }

    }

    /**
     * <h2>更新定时任务</h2>
     *
     * @param config {@link ScheduleJobConfig}
     */
    public void update(ScheduleJobConfig config) {

        log.info("更新定时任务，定时任务名称->[{}]，定时任务组名称->[{}]，七子表达式->[{}]",
                config.getJobName(),
                config.getJobGroupName(),
                config.getExpression()
        );

        try {
            // 获取到对应任务的触发器
            TriggerKey triggerKey = TriggerKey.triggerKey(config.getJobName(), config.getJobGroupName());

            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(config.getExpression())
                    // 不触发立即执行，等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
                    .withMisfireHandlingInstructionDoNothing();

            // 重新构建任务的触发器trigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger
                    .getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder)
                    .build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);

        } catch (SchedulerException e) {
            throw new ScheduleJobException(String.format("更新Quartz中的定时任务失败，原因：%s", e.getMessage()));
        }

    }

    /**
     * <h2>暂停定时任务</h2>
     *
     * @param config {@link ScheduleJobConfig}
     */
    public void pause(ScheduleJobConfig config) {

        log.info("暂停定时任务，定时任务名称->[{}]，任务组名称->[{}]", config.getJobName(), config.getJobGroupName());

        try {
            JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ScheduleJobException(String.format("暂停Quartz中的定时任务失败，原因：%s", e.getMessage()));
        }

    }

    /**
     * <h2>恢复定时任务</h2>
     *
     * @param config {@link ScheduleJobConfig}
     */
    public void resume(ScheduleJobConfig config) {

        log.info("恢复定时任务，定时任务名称->[{}]，任务组名称->[{}]", config.getJobName(), config.getJobGroupName());

        try {
            JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ScheduleJobException(String.format("恢复Quartz中的定时任务失败，原因：%s", e.getMessage()));
        }

    }

    /**
     * <h2>移除quartz中的定时任务</h2>
     *
     * @param config {@link ScheduleJobConfig}
     */
    public void delete(ScheduleJobConfig config) {

        log.info("删除定时任务，定时任务名称->[{}]，任务组名称->[{}]", config.getJobName(), config.getJobGroupName());

        try {
            scheduler.deleteJob(new JobKey(config.getJobName(), config.getJobGroupName()));
        } catch (Exception e) {
            e.printStackTrace();
            throw new ScheduleJobException(String.format("删除Quartz中的定时任务失败，原因：%s", e.getMessage()));
        }

    }

}
